home *** CD-ROM | disk | FTP | other *** search
- Path: news.belwue.de!uzwil!kuehl
- From: kuehl@uzwil.informatik.uni-konstanz.de (Dietmar Kuehl)
- Newsgroups: comp.lang.c++
- Subject: Re: Deriving class from IOSTREAMs
- Date: 16 Apr 1996 00:26:09 GMT
- Organization: FakultΣt fⁿr Mathematik und Informatik
- Message-ID: <4kupf1$720@news.BelWue.DE>
- References: <4ku9qa$7mt@bcarh8ab.bnr.ca>
- Reply-To: dietmar.kuehl@uni-konstanz.de
- NNTP-Posting-Host: uzwil.informatik.uni-konstanz.de
- X-Newsreader: TIN [version 1.2 PL2]
-
- Hi,
-
- Jim Cobban (jcobban@bnr.ca) wrote:
- : I am trying to define a class which has the following characteristics:
-
- : 1) It supports the insertion (<<) operator of the ostream class.
- : 2) Output is organized into units of work. No part of a unit of work
- : can be written to the output device until the unit of work is complete.
- : Then all of the text in the unit of work must be placed on the same line
- : of output. In other words if there is enough room on the current line
- : to hold all of the text then it will be printed on the current line,
- : otherwise a new line is started and the text is written on the new line.
- : 3) When a new line is started, including the very first line in the output,
- : an application specified prefix is written before the first unit of
- : work.
-
- : The first requirement dictates that my class be derived directly or
- : indirectly from ostream.
-
- This is already the problem! You are not supposed to derive from
- 'ostream'. 'ostream' is not intended to be used as a base class except
- for creational purposes! If you want to create a new "external
- representation" you should derive from 'streambuf'. You can than use
- the specialized 'streambuf' to instantiate an 'ostream' (or create a
- class derived from 'ostream' which does so automatically; this is the
- only reason to derive from 'ostream').
-
- : The second requirement seems to me to dictate that
- : my class be derived, in particular, from ostrstream, which provides a buffer
- : in which output can be held until a unit of work is complete.
-
- The buffer management is basically implemented by 'streambuf' so you
- don't need to use 'ostrstream' (it's use is deprecated anyway; it is
- superseeded by 'ostringstream' which is unfortunately not yet part of
- all libraries shipped with the compilers).
-
- : I would like
- : the end of a unit of work to be signalled by a manipulator, but I have had a
- : great deal of difficulty in getting that to work.
-
- This becomes quite easy with the approach I mentioned above. I won't
- discuss your approach, as it is not the way to go anyway. Instead you
- should do something like done by the code I have appended to this
- article (this is probably not the exact behavior you want because I
- haven't completely understood what you want to do to the lines...).
- Note, that the code below is not tested very well: I have just tested
- that it performs some basic stuff. It is likely that there are quite a
- few bugs. Also, there are only very few comments. For more documented
- examples, have a look at
- <http://www.informatik.uni-konstanz.de/~kuehl/c++/iostream>: This page
- references two other examples of new "external representations", namely
- a 'wstream' writing to a GUI window (in this case a Motif 'TextWidget')
- and a 'prfxstream' writing and reading lines with a prefix.
- --
- dietmar.kuehl@uni-konstanz.de
- http://www.informatik.uni-konstanz.de/~kuehl/
- I am a realistic optimist - that's why I appear to be slightly pessimistic
-
- // <!!-*-C++-*- file: workstream.cc --->
- // <!!------------------------------------------------------------------------->
- // <!! Copyright (C) 1996 Dietmar Kuehl >
- // <!! Universitaet Konstanz, Lehrstuhl fuer praktische Informatik I >
- // <!!>
- // <!! This file is free software; you can redistribute it and/or modify >
- // <!! it under the terms of the GNU General Public License as published by >
- // <!! the Free Software Foundation; either version 2 of the License, or >
- // <!! (at your option) any later version. >
- // <!!>
- // <!! This program is distributed in the hope that it will be useful, >
- // <!! but WITHOUT ANY WARRANTY; without even the implied warranty of >
- // <!! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the >
- // <!! GNU General Public License for more details. >
- // <!!------------------------------------------------------------------------->
-
- // Author: Dietmar Kⁿhl dietmar.kuehl@uni-konstanz.de www.informatik.uni-konstanz.de/~kuehl
- // Title: A stream writing when the manipulator 'endw' is applied.
-
- //------------------------------------------------------------------------------
-
- #include <iostream.h>
- #include <cstring>
-
- class workbuf: public streambuf
- {
- private:
- static const int buf_size = 1024;
-
- streambuf *sbuf; // the actual external representation
- char const *prefix; // the line to be written as a prefix
-
- workbuf(workbuf const &);
- workbuf operator= (workbuf const &);
-
- void increase_buffer(int add_size = buf_size); // increases the buffer
- void write_buffer(); // write the buffer to the actual representation
-
- public:
- workbuf(char const *prfx, streambuf *sb);
- ~workbuf();
-
- int overflow(int c);
- int xsputn(const char *s, int n);
-
- virtual void end_work(); // called by the manipulator 'endw'
- };
-
- workbuf::workbuf(char const *prfx, streambuf *sb):
- sbuf(sb),
- prefix(strcpy(new char[strlen(prfx) + 1], prfx))
- {
- char *buffer = new char[buf_size];
- setp(buffer, buffer + buf_size);
- }
-
- workbuf::~workbuf()
- {
- if (pbase() != epptr())
- write_buffer();
- delete[] pbase();
- setp(0, 0);
- delete[] prefix;
- }
-
- void workbuf::increase_buffer(int add_size)
- {
- int size = epptr() - pbase();
- char *new_buf = new char[size + add_size];
- memcpy(new_buf, pbase(), size);
- delete[] pbase();
- setp(new_buf, new_buf + size + add_size);
- pbump(size);
- }
-
- void workbuf::write_buffer()
- {
- sbuf->sputn(prefix, strlen(prefix));
- sbuf->sputn(pbase(), pptr() - pbase());
- sbuf->sputc('\n');
- sbuf->sync();
-
- setp(pbase(), epptr());
- }
-
- int workbuf::overflow(int c)
- {
- increase_buffer();
- return sputc(c);
- }
-
- int workbuf::xsputn(const char *s, int n)
- {
- int left = epptr() - pptr();
- if (left < n)
- increase_buffer(n - left > buf_size? n - left + buf_size: buf_size);
- memcpy(pptr(), s, n);
- pbump(n);
- return n;
- }
-
- void workbuf::end_work()
- {
- write_buffer();
- }
-
- //------------------------------------------------------------------------------
-
- class oworkstream: public ostream
- {
- friend ostream &endw(ostream &);
-
- private:
- static int data_idx;
-
- streambuf *sbuf;
-
- oworkstream(oworkstream const &);
- oworkstream &operator=(oworkstream const &);
- public:
- oworkstream(char const *prefix, streambuf *sb);
- ~oworkstream();
- };
-
- int oworkstream::data_idx = ios::xalloc();
-
- oworkstream::oworkstream(char const *prefix, streambuf *sb):
- ostream(new workbuf(prefix, sb)),
- sbuf(rdbuf())
- {
- pword(data_idx) = rdbuf();
- }
-
- oworkstream::~oworkstream()
- {
- delete sbuf;
- }
-
- ostream &endw(ostream &out)
- {
- if (out.pword(oworkstream::data_idx) == out.rdbuf())
- {
- workbuf *wb = (workbuf *)out.rdbuf();
- wb->end_work();
- }
- else
- cerr << "'endw' manipulator applied to non-'oworkstream'!\n";
- return out;
- }
-
- //------------------------------------------------------------------------------
-
- int main()
- {
- oworkstream out("prefix: ", cout.rdbuf());
-
- out << "hello world" << endw;
- out << "goodbye";
- return 0;
- }
-